/* Sección de definiciones */
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "./include/grammaticCDT.h"

void printGramaticFormat();
void printProductionFormat();
void getResults(grammaticADT g);
grammaticADT g;
%}

NTERMINAL 					([A-Z])
TERMINAL 					([a-z]|[0-9])
INITSYMBOL 					([A-Z])
SPACES 						([\t|\n| ])
GNAME 						[a-zA-Z]([a-zA-Z0-9 ]*)
BEGINNING 					{SPACES}*"="{SPACES}*"("{SPACES}*"{"{SPACES}*
PRE							({NTERMINAL}|{TERMINAL})+
POST 						(({TERMINAL}|{NTERMINAL})|\\)+
PRODUCTION					{PRE}({SPACES}*)">"({SPACES}*){POST}({SPACES}*)(\|({SPACES}*){POST}({SPACES}*))*

%s Q1 
%x Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 TRAMPA

%%
<INITIAL>.							BEGIN TRAMPA;
<INITIAL>{SPACES}+					;
<INITIAL>{GNAME}					{fprintf(yyout, "Grammar \"%s\" analysis began...\n\n", yytext);g = NewGrammatic(yytext); BEGIN Q1;}
<Q1>{BEGINNING}						BEGIN Q2;
<Q1>.								BEGIN TRAMPA;
<Q2>{NTERMINAL}						{AddVN(g, yytext); BEGIN Q3;}
<Q2>{SPACES}+						;
<Q2>.								{
										fprintf(yyout, "Invalid non terminal symbol %s\n", yytext);
										fprintf(yyout, "PROGRAM TERMINATED\n");
										FreeGrammaticADT(g);
										BEGIN TRAMPA;
									}
<Q3>","								BEGIN Q2;
<Q3>{SPACES}+						;
<Q3>"}"({SPACES})*","({SPACES})*"{"	BEGIN Q4;
<Q3>.								{
										fprintf(yyout, "Syntax error closing non-terminal symbol group\n");
										fprintf(yyout, "PROGRAM TERMINATED\n");
										FreeGrammaticADT(g);
										BEGIN TRAMPA;
									}
<Q4>{TERMINAL}						{AddVT(g, yytext), BEGIN Q5;}
<Q4>{SPACES}+						
<Q4>.								{
										fprintf(yyout, "Invalid terminal symbol %s\n", yytext); 
										fprintf(yyout, "PROGRAM TERMINATED\n");
										FreeGrammaticADT(g);
										BEGIN TRAMPA;
									}
<Q5>","								BEGIN Q4;
<Q5>{SPACES}+						;
<Q5>"}"({SPACES})*","({SPACES})*	BEGIN Q6;
<Q5>.								{
										fprintf(yyout, "Syntax error closing terminal symbol group\n"); 
										fprintf(yyout, "PROGRAM TERMINATED\n");
										FreeGrammaticADT(g);
										BEGIN TRAMPA;
									}
<Q6>{INITSYMBOL}					{
										if (AddInitialSymbol(g, yytext) == ERR)
										{	
											fprintf(yyout, "Syntax error, initial symbol %s does not belong to non-terminal symbol group\n", yytext);
											fprintf(yyout, "PROGRAM TERMINATED\n");
											FreeGrammaticADT(g);
											BEGIN TRAMPA; 
										}
										else
											BEGIN Q7;
									}
<Q6>{SPACES}+						;
<Q6>.								{
										fprintf(yyout, "Invalid initial symbol %s\n", yytext); 
										fprintf(yyout, "PROGRAM TERMINATED\n");
										FreeGrammaticADT(g);
										BEGIN TRAMPA;
									}
<Q7>","({SPACES})*"{"({SPACES})*	BEGIN Q8;
<Q7>{SPACES}+						;
<Q7>.								{
										fprintf(yyout, "Syntax error in opening production group\n"); 
										fprintf(yyout, "PROGRAM TERMINATED\n");
										FreeGrammaticADT(g);
										BEGIN TRAMPA;
									}
<Q8>{PRODUCTION}					{
										if (AddProduction(g, yytext) == ERR)
										{
											fprintf(yyout, "Syntax error in the production %s\n", yytext);
											fprintf(yyout, "PROGRAM TERMINATED\n");
											FreeGrammaticADT(g);
											BEGIN TRAMPA;
										}
										else
											BEGIN Q9;
									}
<Q8>{SPACES}+						;
<Q8>.								{
										fprintf(yyout, "Invalid production %s\n", yytext);
										fprintf(yyout, "PROGRAM TERMINATED\n");
										BEGIN TRAMPA;
									}
<Q9>","								BEGIN Q8;
<Q9>"}"({SPACES}*)")"({SPACES}*)	{getResults(g);FreeGrammaticADT(g);g = NULL;BEGIN 0;}
<Q9>{SPACES}+						;
<Q9>.								{
										fprintf(yyout, "Syntax error closing grammar\n");
										fprintf(yyout, "PROGRAM TERMINATED\n");
										BEGIN TRAMPA;
									}
<TRAMPA>.							;


%%


int 
main(int argc, char * argv[]) 
{
	FILE * inputFile;
	
	yyout = stdout;
	
	if (argc > 1)
	{

		
		if ( (inputFile = fopen(argv[1], "r+")) == NULL )
		{
			fprintf(yyout, "File of name: %s does not exist\n", argv[1]);
			return 1;
		}
		
		yyin = inputFile;
	}
	else
	{
		fprintf(yyout, "Argument one missing, file path was expected\n");
		return 1;
	}
	
	yylex();
	
	return 0;
}


void
getResults(grammaticADT g)
{
	char * gname;
	char errmsg[50] = {'\0'};
	
	gname = GetName(g);	
	
	if (!IsValidGrammatic(g, errmsg))
	{
		fprintf(yyout, "Syntax error in the grammar %s, reason: %s\n", gname, errmsg);
		return;
	}

	ShowVNs(g, yyout);
	ShowVTs(g, yyout);
	ShowInitialSymbol(g, yyout);	
	ShowProductions(g, yyout);

	
	if (IsRegularGrammatic(g))
	{
		fprintf(yyout, "The grammar %s, is regular %s oriented\n", gname, GrammaticDirection(g) == LEFT ? "LEFT" : "RIGHT");
	}
	else
	{
		fprintf(yyout, "The grammar %s, is not regular\n", gname);
	}
	
	return;	
}
